上一篇講完了 Flask 的本體,這篇開始就要開始講 Flask 的插件了。Flask 從初始版本(2010/04/01)發布以來,已經過去了 10 年左右,許多人為了能夠更加快速的開發,貢獻了需多方便使用的插件。而這篇要介紹第一個插件就是 — Flask-SocketIO。
講到現在有沒有發現 HTTP 協議的模式基本上是 Client 打一下回應一下,再打一下再回應一下,而現在如果 Server 端需要主動傳資訊給 Client,就必須等使用者下一次打的時候,包再回應裡面再回傳給 Client。
早期各種網路應用還不發達的時候,也許並沒有問題,但是現在各種各樣的應用出來之後,這樣的模式就有點不足了,所以就有了 WebSocket 這個東西,而 WebSocket 相比 HTTP 協議,WebSocket 有著以下的優點:
不過 WebSocket 只是協議,需要有一個程式去實作它,並且作為套件供其他程式使用,而且前後端都需要有個程式去實作,否則無法達成雙向通訊。在前端處理這些東西的通常都是 JavaScript ,所以 JavaScript 中 WebSocket 的套件叫做 Socket.IO ,而在後端的 Flask 中也有相對應的套件,而那個套件就是這篇的主題 — Flask-SocketIO。
總而言之
WebSocket -> 協議
Socket.IO -> JavaScript 的前端實作
Flask-SocketIO -> Flask 框架的後端實作
大概就醬
首先,因為是插件,所以並沒有包含在 Flask 裡面,需要另外安裝。當然還是使用我們熟悉的 pip 來安裝啦,不過除了安裝 Flask-SocketIO 以外,還要安裝 Flask-SocketIO 依賴的非同步服務 eventlet。
$ pipenv install flask-socketio eventlet
既然說到了安裝,那就先來說一下後端如何使用好了(因為前端的話只要使用 JavaScript 然後透過 CDN 導入就可以了),假設現在要做一個超簡單的聊天室(終於不是拿前面的那坨來改了,記得 pipenv install flask
喔),架構長這樣(雖然不是拿前面那坨改,但是還是有幾個可以複製過來沿用):
ithome_chatroom
├── templates
│ └── index.html # 聊天室首頁
├── app.py # 主要的檔案(很爛的形容我知道,我就不會形容啊)
├── configs.py # 設定檔
├── Pipfile # 不管它,建立虛擬環境時自己會出現
└── Pipfile.lock # 不管它,安裝套件時自己會出現
首先當然是做好聊天室後端啦,後端當然是寫在 app.py
裡面。
app.py
from flask import Flask, render_template
from flask_socketio import SocketIO # 加上這行
import configs
app = Flask(__name__)
app.config.from_object(configs)
socketio = SocketIO(app) # 加上這行
@app.route('/')
def index():
return render_template('index.html')
@socketio.on('send')
def chat(data):
socketio.emit('get', data)
@socketio.on('test')
def test():
socketio.send("test")
if __name__ == "__main__":
socketio.run(app)
處理好後端之後呢,接著當然就是前端啦,不過前端有點特殊,剛剛前面講過前端需要有個程式來處理,不過這個架構上看起來並沒有前端的處理程式阿?那是因為前端的處理程式可以在渲染前端時,透過 CDN 導入後在執行,而只需要在 .html
檔裡面加上一句就可以了(不是我偷懶不講啦,只是弄個小小的實驗而已沒必要搞得這麼複雜啦)。
那要怎麼找 CDN 來導入呢?可以從下面兩個(Socket.IO 是必要的,JQuery 可以不必,只是因為我喜歡用 JQuery 而已,沒辦法,JavaScript 語法太長了)連結進去,找到隨便一個版本(我推薦是用紅色背景的那個),然後找到 </>
這樣的案件,點下去就複製好了。
複製好了之後,來到 index.html
貼上,再加上幾行就 OK 了。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>WebSocket test</title>
<!-- JQuery 的 CDN 連結 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"
integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Socket.IO 的 CDN 連結 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.js"
integrity="sha512-WL6WGKMPBiM9PnHRYIn5YEtq0Z8XP4fkVb4qy7PP4vhmYQErJ/dySyXuFIMDf1eEYCXCrQrMJfkNwKc9gsjTjA=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- Socket.IO 的使用 -->
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
// Socket.IO Start connect
var socket = io.connect();
// Socket.IO send message
$("#send").click(function (e) {
// Send message
socket.emit('send', $('#message').val())
// Clear input field
$('#message').val('')
});
// Socket.IO get message
socket.on('get', function (data) {
$('#chat_content').append('<p>I say: ' + data + '</p>');
});
// Socket.IO get test
socket.on("message", function (data) {
$('#chat_content').append('<p>System : ' + data + '</p>');
});
// Socket.IO send test
$("#test").click(function (e) {
socket.emit('test')
});
});
</script>
</head>
<body>
<h1>Hello</h1>
<h2>WebSocket test</h2>
<form>
<fieldset>
<legend>Message</legend>
<input type="text" id="message" name="message" />
<input type="button" id="send" value="Send" />
<input type="button" id="test" value="Test" />
</fieldset>
</form>
<hr />
<div id='chat_content'></div>
</body>
</html>
這樣子輸入完就可以了,簡單來說 send
跟 emit
可以傳送事件,其中send
是傳送未命名事件;而 emit
是傳送命名事件。on
則是監聽有無事件發生。
那就來看執行後會發生什麼事吧。
看起來沒有發生什麼對吧,再 input 輸入一點東西後按下 Send 看看。
如果再按下旁邊的 Test 呢?
是不是沒有看出來哪裡厲害對吧,同時開兩個分頁再重複上面的操作後你就懂了。
那麼就大概這樣,WebSocket 還有很多可以說的,但是如果全部塞在同一篇的話就太多了,而且我後面還有其他插件要說,所以 WebSocket 就先介紹到這裡。
大家掰~掰~